
#include <stdbool.h> 

#include "xgui_config.h"

#include "gui.h"
#include "gui_core.h"
#include "gui_transition.h"
#include "gui_port.h"


#define FLAG_CREATE                 0x0001
#define FLAG_INVALIDATE             0x0002 

#define TYPE_CREATE_SINGLE          0x00
#define TYPE_CREATE_SUB             0x01
#define TYPE_CREATE_SWITCH          0x02 
#define TYPE_CREATE_NAVIGATE        0x03 
#define TYPE_CREATE_FLING           0x04 
#define TYPE_CREATE_TRANSITION      0x05 
#define TYPE_CREATE_RETURN          0x06 

#define TYPE_PAINT_UPDATE           0x00
#define TYPE_PAINT_UPDATE_MANUAL    0x01
#define TYPE_PAINT_FLING            0x02
#define TYPE_PAINT_NAVIGATE         0x03 
//#define TYPE_PAINT_PART             0x04 
#define TYPE_PAINT_TRANSITION       0x05
#define TYPE_PAINT_TRANSITION_RECOVERY  0x06
#define TYPE_PAINT_UPDATE_EVENT     0x07 

static gui_view_ctl_t   gui_view_ctl; 

#if GUI_USER_SYNC_HANDLER
#
static bool                 invalidate = false;
static uint8_t              draw_func ;
#endif 

static bool             m_create_req = false;
static uint8_t          create_type ; 

static bool             m_paint_req = false; 
static uint8_t          m_paint_type ; 

static bool             m_turn_off_req = false; 
static bool             m_is_turn_on = false; 

bool gui_is_turn_on(void)
{
    return m_is_turn_on; 
}

// create a view 
void gui_view_create(
    const gui_view_t * p_ui_cur
)
{
    gui_view_ctl.p_ui_cur = p_ui_cur;

    create_type = TYPE_CREATE_SINGLE;
    if( m_create_req == false )
    {
        m_create_req = true;
        gui_port_send_msg();
    }
}

void gui_view_create_return( const gui_view_t * p_ui_cur ) 
{
    gui_view_ctl.p_ui_cur = p_ui_cur;

    create_type = TYPE_CREATE_RETURN;
    if( m_create_req == false )
    {
        m_create_req = true;
        gui_port_send_msg();
    }
}

void gui_view_create_sub(
    const gui_view_t * p_ui_cur,
    const gui_view_t * p_ui_sub
)
{
    gui_view_ctl.p_ui_cur = p_ui_cur;
    gui_view_ctl.p_ui_sub = p_ui_sub;

    create_type = TYPE_CREATE_SUB;
    if( m_create_req == false )
    {
        m_create_req = true;
        gui_port_send_msg();
    }
}


void gui_view_create_switch(
    const gui_view_t * p_ui_cur,
    const gui_view_t * p_ui_sub,
    int op
)
{
    gui_view_ctl.p_ui_cur = p_ui_cur;
    gui_view_ctl.p_ui_sub = p_ui_sub;
    gui_view_ctl.OP       = op;

    create_type = TYPE_CREATE_SWITCH;
    if( m_create_req == false )
    {
        m_create_req = true;
        gui_port_send_msg();
    }
}

void gui_view_create_navigate(
    const gui_view_t * p_ui_cur,
    const gui_view_t * p_ui_sub,
    int16_t from_x,
    int16_t from_y,
    int16_t to_x,
    int16_t to_y
)
{
    gui_view_ctl.p_ui_cur = p_ui_cur;
    gui_view_ctl.p_ui_sub = p_ui_sub;
    gui_view_ctl.fromX = from_x;
    gui_view_ctl.fromY = from_y;
    gui_view_ctl.toX = to_x;
    gui_view_ctl.toY = to_y;

    create_type = TYPE_CREATE_NAVIGATE;

    if( m_create_req == false )
    {
        m_create_req = true;
        gui_port_send_msg();
    }
}

void gui_view_create_transition(
    const gui_view_t * p_ui_cur,
    const gui_view_t * p_ui_sub,
    const gui_view_t * p_ui_transition,
    int16_t x,
    int16_t y
)
{
    gui_view_ctl.p_ui_cur = p_ui_cur;
    gui_view_ctl.p_ui_sub = p_ui_sub;
    gui_view_ctl.p_ui_transition = p_ui_transition;

    gui_view_ctl.deltaX = x;
    gui_view_ctl.deltaY = y;
    create_type = TYPE_CREATE_TRANSITION;

    if( m_create_req == false )
    {
        m_create_req = true;
        gui_port_send_msg();
    }
}

// void gui_view_create_idle( const gui_view_t * p_ui_cur )
// {
//     gui_view_ctl.p_ui_cur = p_ui_cur;
    
// }

#if GUI_USER_SYNC_HANDLER
void gui_view_set_sync_handle(uint8_t type)
{
    invalidate = true;
}
#endif

void gui_view_task_handler(void)
{
    // require to turn off 
    if( m_turn_off_req )
    {
        m_paint_req = false;
        m_create_req = false;
        m_turn_off_req = false;
        
        uint32_t ret = gui_core_view_lifetime_end();
        gui_port_lcd_turn_off( ret );
        // if( gui_core_view_lifetime_end()  ) 
        // {
        //     gui_port_lcd_turn_off( true );
        // }
        // else 
        // {
        //     gui_port_lcd_turn_off( false );
        // }
        
        m_is_turn_on = false; 
    }
    
    #if GUI_USER_SYNC_HANDLER
    if( invalidate)
    {
        // invalidate single/double/part 
    }
    #endif
    
    // required to create a view 
    if( m_create_req )
    {
        gui_view_ctl_t ctl ;
        uint8_t type = create_type;

        memcpy( &ctl, (gui_view_ctl_t*)&gui_view_ctl, sizeof( gui_view_ctl_t ));
        
        m_create_req = false; /// create & do not update         
        
        if( m_is_turn_on == false ) 
        {
            gui_port_lcd_turn_on_prepare();
        }
        switch( type )
        {
            case TYPE_CREATE_SINGLE:
            gui_core_view_create( ctl.p_ui_cur, false );
            break;

            case TYPE_CREATE_RETURN:
            gui_core_view_create( ctl.p_ui_cur, true );
            break;

            case TYPE_CREATE_SUB:
            gui_core_view_create_sub( ctl.p_ui_cur, ctl.p_ui_sub );
            break;

            case TYPE_CREATE_SWITCH:
            gui_core_view_create_switch( ctl.p_ui_cur, ctl.p_ui_sub, ctl.OP );
            break;

            case TYPE_CREATE_NAVIGATE:
            gui_core_view_create_navigate(
                                            ctl.p_ui_cur, ctl.p_ui_sub,
                                            ctl.fromX, ctl.fromY,
                                            ctl.toX, ctl.toY
                                        );
            break;

            case TYPE_CREATE_TRANSITION:
            gui_transition_set(
                                    ctl.p_ui_cur, ctl.p_ui_sub, ctl.p_ui_transition, 
                                    ctl.deltaX, ctl.deltaY
                                );
            gui_core_view_create_transition();
            break;
        }

        if( m_is_turn_on == false ) 
        {
            m_is_turn_on = true;
            gui_port_lcd_turn_on_ready(); 
        }
        return; 
    }

    // required to paint 
    if( m_paint_req )
    {
        uint8_t type = m_paint_type;
        m_paint_req = false; 
        
        if( m_is_turn_on == false ) 
        {
            gui_port_lcd_update_init(); // DMA require init 
        }

        switch( type ) 
        {
            case TYPE_PAINT_UPDATE:
            gui_core_view_update_auto();
            break;

            case TYPE_PAINT_UPDATE_MANUAL:
            gui_core_view_update( true );
            break;

            case TYPE_PAINT_FLING:
            gui_core_view_update_fling();
            break;

            case TYPE_PAINT_NAVIGATE:
            gui_core_view_update_navigate();
            break;
            
//            case TYPE_PAINT_PART:
//            gui_core_view_update_part();
//            break;

            case TYPE_PAINT_TRANSITION:
            gui_core_view_on_transition_update();
            break;

            case TYPE_PAINT_TRANSITION_RECOVERY:
            gui_core_view_on_transition_recovery();
            break;

            case TYPE_PAINT_UPDATE_EVENT:
            gui_core_view_update( false );
            break;
        }
    }
}


void gui_update(void)
{    
    m_paint_type = TYPE_PAINT_UPDATE;
    if( m_paint_req == false  )
    {        
        m_paint_req = true;
        gui_port_send_msg();
    }    
}
void gui_update_manual(void)
{   
    m_paint_type = TYPE_PAINT_UPDATE_MANUAL;
    if( m_paint_req == false )
    {        
        m_paint_req = true;
        gui_port_send_msg();
    }    
}
void gui_update_event(void) 
{
    m_paint_type = TYPE_PAINT_UPDATE_EVENT;
    if( m_paint_req == false )
    {        
        m_paint_req = true;
        gui_port_send_msg();
    } 
}

void gui_update_fling(void)
{    
    m_paint_type = TYPE_PAINT_FLING;
    if( m_paint_req == false )
    {        
        m_paint_req = true;
        gui_port_send_msg();
    }    
}
void gui_update_navigate(void)
{    
    m_paint_type = TYPE_PAINT_NAVIGATE;
    if( m_paint_req == false ) 
    {        
        m_paint_req = true;
        gui_port_send_msg();
    }
}

//void gui_update_part(void)
//{     
//    if( m_paint_req == false )
//    {
//        m_paint_type = TYPE_PAINT_PART;
//        m_paint_req = true;
//        gui_port_send_msg();
//    }
//}

void gui_update_transition(void)
{
    if( m_paint_req == false )
    {
        m_paint_type = TYPE_PAINT_TRANSITION;
        m_paint_req = true;
        gui_port_send_msg();
    }
}

void gui_recovery_transition(void)
{
    // if( m_paint_req == false )
    {
        m_paint_type = TYPE_PAINT_TRANSITION_RECOVERY;
        m_paint_req = true;
        gui_port_send_msg();
    }
}

void gui_lifetime_end(void)
{
    if( m_turn_off_req == false ) 
    {
        m_turn_off_req = true;
        gui_port_send_msg();
    }
}

// not test yet 
gui_view_t* gui_get_view_addr_by_name( const char* name)
{
    extern unsigned int Image$$GUI_MENU_DATA$$RO$$Base;
    extern unsigned int Image$$GUI_MENU_DATA$$RO$$Length;
    gui_view_t* pRet = (void *)&Image$$GUI_MENU_DATA$$RO$$Base;
    
    for( uint32_t i = 0; i < ((unsigned int)&Image$$GUI_MENU_DATA$$RO$$Length) / sizeof(gui_view_t) ; i ++ )
    {
        if( strcmp( name, pRet->name ) == 0 )
        {
            return pRet;
        }
        pRet ++;
    }
    
    return NULL;    
}


